package com.cskt.itripbiz.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cskt.common.condition.AddHotelOrderCondition;
import com.cskt.common.condition.SearchOrderCondition;
import com.cskt.common.condition.ValidateRoomStoreCondition;
import com.cskt.common.constants.ErrorCodeEnum;
import com.cskt.common.constants.SystemConstants;
import com.cskt.common.exception.ServiceException;
import com.cskt.common.vo.*;
import com.cskt.entity.HotelOrder;
import com.cskt.entity.HotelRoom;
import com.cskt.entity.OrderLinkUser;
import com.cskt.entity.UserLinkUser;
import com.cskt.itripbiz.service.HotelOrderService;
import com.cskt.itripbiz.service.HotelRoomService;
import com.cskt.itripbiz.service.HotelTempStoreService;
import com.cskt.itripbiz.service.OrderLinkUserService;
import com.cskt.mapper.HotelOrderMapper;
import com.cskt.util.BigDecimalUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.cskt.util.MD5.MD5;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service
public class HotelOrderServiceImpl extends ServiceImpl<HotelOrderMapper, HotelOrder> implements HotelOrderService {

    private final String orderProcessOK = "{\"1\":\"订单提交\",\"2\":\"订单支付\",\"3\":\"支付成功\",\"4\":\"入住\",\"5\":\"订单点评\",\"6\":\"订单完成\"}";
    private final String orderProcessCancel = "{\"1\":\"订单提交\",\"2\":\"订单支付\",\"3\":\"订单取消\"}";
    @Resource
    private HotelTempStoreService hotelTempStoreService;

    @Resource
    private OrderLinkUserService orderLinkUserService;

    @Resource
    private HotelRoomService hotelRoomService;

    @Override
    public RoomStoreVO getRoomStoreVOByCondition(ValidateRoomStoreCondition condition) {
        RoomStoreVO roomStoreVO = baseMapper.selectRoomStoreVOByCondition(condition);

        if (null!=roomStoreVO){
            //填充其他无法查询得到的数据
            roomStoreVO.setCheckInDate(condition.getCheckInDate());
            roomStoreVO.setCheckOutDate(condition.getCheckOutDate());
            roomStoreVO.setCount(1);
        }
        return roomStoreVO;
    }

    @Override
    public PersonalHotelOrderVO getPersonalHotelOrderVOByOrderId(Long orderId) {
        //先查出hotelOrder，再完成类型转换
        HotelOrder hotelOrder = this.getById(orderId);
        if (hotelOrder==null){
            //没有相关订单信息
            throw new ServiceException(ErrorCodeEnum.BIZ_NO_HAVE_ORDER_INFO);
        }else {
            PersonalHotelOrderVO personalHotelOrderVO = new PersonalHotelOrderVO();
            BeanUtils.copyProperties(hotelOrder,personalHotelOrderVO);
            //查询预订的房间信息
            HotelRoom hotelRoom = hotelRoomService.getById(hotelOrder.getRoomId());
            if (hotelOrder!=null){
                personalHotelOrderVO.setRoomPayType(hotelRoom.getPayType());
            }
            //根据当前的订单状态确定订单接下来的流程
            // sysConfig.orderProcessOK = {"1":"订单提交","2":"订单支付","3":"支付成功","4":"入住","5":"订单点评","6":"订单完成"}
            // sysConfig.orderProcessCancel = {"1":"订单提交","2":"订单支付","3":"订单取消"}
            Integer orderStatus = hotelOrder.getOrderStatus();
            switch (orderStatus){
                //待支付
                case 0:
                    personalHotelOrderVO.setOrderProcess(orderProcessOK);
                    personalHotelOrderVO.setProcessNode("2");
                    break;
                case 1:
                    personalHotelOrderVO.setOrderProcess(orderProcessCancel);
                    personalHotelOrderVO.setProcessNode("3");
                    break;
                case 2:
                    personalHotelOrderVO.setOrderProcess(orderProcessOK);
                    personalHotelOrderVO.setProcessNode("3");
                    break;
                case 3:
                    personalHotelOrderVO.setOrderProcess(orderProcessOK);
                    personalHotelOrderVO.setProcessNode("5");
                    break;
                case 4:
                    personalHotelOrderVO.setOrderProcess(orderProcessOK);
                    personalHotelOrderVO.setProcessNode("6");
                    break;
                default:
                    personalHotelOrderVO.setOrderProcess(null);
                    personalHotelOrderVO.setProcessNode(null);
                    break;
            }
            return personalHotelOrderVO;
        }
    }

    @Override
    public PersonalOrderRoomVO getPersonalOrderRoomVOByOrderId(Long orderId) {
        PersonalOrderRoomVO personalOrderRoomVO = baseMapper.selectPersonalOrderRoomVOByOrderId(orderId);
        if (StringUtils.isEmpty(personalOrderRoomVO)){
            throw new ServiceException(ErrorCodeEnum.BIZ_DATA_NULL);
        }
        return personalOrderRoomVO;
    }

    @Override
    public Page<ListHotelOrderVO> getOrderPageByCondition(SearchOrderCondition condition) {
        //分页列表
        List<ListHotelOrderVO> listHotelOrderVOS = baseMapper.selectOrderVOListByCondition(condition);
        //总数量
        Integer total = baseMapper.selectOrderVOCountByCondition(condition);
        //封装为分页对象
        Page<ListHotelOrderVO> page = new Page<>();
        page.setTotal(total);
        page.setRows(listHotelOrderVOS);
        return page;
    }

    @Override
    public ModifyHotelOrderVO getModifyHotelOrderVOByOrderId(Long orderId) {
        HotelOrder order = this.getById(orderId);
        //没有订单信息
        if (order==null){
            throw new ServiceException(ErrorCodeEnum.BIZ_NO_HAVE_ORDER_INFO);
        }
        //完成类型转换
        ModifyHotelOrderVO modifyHotelOrderVO = new ModifyHotelOrderVO();
        BeanUtils.copyProperties(order,modifyHotelOrderVO);
        //根据id查询入住人
        LambdaQueryWrapper<OrderLinkUser> lambdaQueryWrapper = new QueryWrapper<OrderLinkUser>()
                .lambda().select(OrderLinkUser::getLinkUserId,OrderLinkUser::getLinkUserName)
                .eq(OrderLinkUser::getOrderId,orderId);
        List<OrderLinkUser> orderLinkUserList =
                orderLinkUserService.list(lambdaQueryWrapper);

        List<OrderLinkUserVO> orderLinkUserVOList = orderLinkUserList.stream().map(
                orderLinkUser -> {
                    OrderLinkUserVO orderLinkUserVO = new OrderLinkUserVO();
                    BeanUtils.copyProperties(orderLinkUser,orderLinkUserVO);
                    return orderLinkUserVO;
                }).collect(Collectors.toList());
        modifyHotelOrderVO.setItripOrderLinkUserList(orderLinkUserVOList);
        return modifyHotelOrderVO;
    }

    @Override
    public Map<String, Object> addHotelOrder(AddHotelOrderCondition condition, Long userId) {
        Map<String,Object> returnMap = new HashMap<>();
        // TODO: 2020/10/8 1、判断房间库存是否充足
        Boolean result = hotelTempStoreService.validateRoomStore(condition);
        if (!result){
            //验证不通过 抛出异常
            throw new ServiceException(ErrorCodeEnum.BIZ_ROOM_STORE_NOT_ENOUGH);
        }

        // TODO: 2020/10/8 2、订单数据预处理
        //将生成订单条件类转换为订单实体类
        HotelOrder hotelOrder = new HotelOrder();
        BeanUtils.copyProperties(condition,hotelOrder);
        //添加其他属性
        hotelOrder.setUserId(userId);
        //入住人姓名
        List<UserLinkUser> linkUserList = condition.getLinkUser();
        String linkUserName = linkUserList.stream()
                .map(UserLinkUser::getLinkUserName)
                .collect(Collectors.joining(","));
        hotelOrder.setLinkUserName(linkUserName);
        //订单来源 默认为pc端
        hotelOrder.setBookType(SystemConstants.OrderBookType.WEB);
        //订单的状态为未支付
        hotelOrder.setOrderStatus(SystemConstants.OrderStatus.TO_BE_PAID);
        //订单号，生成规则 （机器码+日期）MD5 ,(商品IDs+毫秒数+1000000的随机数)
        StringBuffer md5String = new StringBuffer().append(hotelOrder.getHotelId())
                .append(hotelOrder.getRoomId())
                .append(System.currentTimeMillis())
                .append(Math.random()*1000000);

        String orderNo = new StringBuffer().append("machineCode")
                .append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")))
                .append(MD5.getMd5(md5String.toString(),16)).toString();
        hotelOrder.setOrderNo(orderNo);
        //订单总金额
        hotelOrder.setPayAmount(getOrderPayAmount(condition.getCount(),condition.getRoomId()));
        //计算入住天数
        int bookingDays = Period.between(condition.getCheckInDate(),condition.getCheckOutDate()).getDays();
        hotelOrder.setBookingDays(bookingDays);
        // TODO: 2020/10/8 3、生成订单
        boolean saveOrUpdateResult = false;
        //如果订单id不为空 完成更新操作
        if (!StringUtils.isEmpty(hotelOrder.getId())){
            //先删除原来已存在的联系人
            orderLinkUserService.removeOrderLinkUserByOrderId(hotelOrder.getId());
            saveOrUpdateResult = this.updateById(hotelOrder);
        }else {
            //否则就更新
            saveOrUpdateResult = this.save(hotelOrder);
        }
        //订单生成成功后还需要添加订单联系人
        if (!saveOrUpdateResult){
            //上面操作失败，则直接抛出异常
            throw new ServiceException(ErrorCodeEnum.SYSTEM_EXECUTION_ERROR);
        }else {
            Long orderId = hotelOrder.getId();
            if (orderId>0){
                List<OrderLinkUser> orderLinkUsers = new ArrayList<>(linkUserList.size());
                linkUserList.forEach(
                        userLinkUser ->{
                            OrderLinkUser orderLinkUser = new OrderLinkUser();
                            BeanUtils.copyProperties(userLinkUser,orderLinkUser);
                            orderLinkUser.setOrderId(orderId);
                            orderLinkUser.setLinkUserId(userLinkUser.getId());
                            orderLinkUsers.add(orderLinkUser);
                        }
                );
                //批量新增
                orderLinkUserService.saveBatch(orderLinkUsers);
            }
        }
        returnMap.put("id",String.valueOf(hotelOrder.getId()));
        returnMap.put("orderNo",hotelOrder.getOrderNo());
        return returnMap;
    }

    private BigDecimal getOrderPayAmount(Integer count, Long roomId) {
        BigDecimal roomPrice = hotelRoomService.getById(roomId).getRoomPrice();
        BigDecimal payAmount = BigDecimalUtil.OpertionASMD(count, roomPrice,
                BigDecimalUtil.BigDecimalOprations.multiply, 2,
                BigDecimal.ROUND_DOWN);
        return payAmount;
    }


}
